import babel, { types as t } from '@babel/core';
import parser from '@babel/parser';
import { CodeGenerator as Generator } from '@babel/generator';
import { prettifyJs } from '.';

export const scriptAstUtil = {
  transform(source: string) {
    return parser.parse(source, {
      sourceType: 'module',
      plugins: ['dynamicImport', 'objectRestSpread']
    });
  },
  getExportDefaultProperties(node: any) {
    let body = node.program.body;
    for (let i = 0; i < body.length; i++) {
      if (body[i].type === 'ExportDefaultDeclaration') {
        return body[i].declaration.properties;
      }
    }
  },
  getNodeFromRootByPath(node: t.Node, path: string) {
    let rootProperties = this.getExportDefaultProperties(node);
    let paths = path.split('.');
    function recursive(properties: any[], paths: any) {
      if (paths.length === 0) {
        throw new Error('util.getNodeFromRootByPath异常，path参数为空');
      }
      for (let i = 0; i < properties.length; i++) {
        if (
          (properties[i].type === 'ObjectProperty' ||
            properties[i].type === 'ObjectMethod') &&
          (properties[i].key.name === paths[0] ||
            properties[i].key.value === paths[0])
        ) {
          if (paths.length === 1) {
            return properties[i];
          }
          paths.splice(0, 1);
          return recursive(properties[i].value.properties, paths);
        }
      }
    }
    return recursive(rootProperties, paths);
  },
  getReturnObjectProperties(node: any) {
    for (let i = 0; i < node.length; i++) {
      if (node[i].type === 'ReturnStatement') {
        return node[i].argument.properties;
      }
    }
  },
  isMatchMethods(n: any, methods: string[]) {
    if (!n) {
      throw new Error(`node can't be null`);
    }
    return (
      t.isCallExpression(n.expression) &&
      t.isMemberExpression(n.expression.callee) &&
      n.expression.callee.object.type === 'Identifier' &&
      t.isIdentifier(n.expression.callee.property) &&
      methods.indexOf(n.expression.callee.property.name) > -1
    );
  },
  transformFromNode(node: t.Node) {
    const result = new Generator(node, {
      jsescOption: {
        quotes: 'single'
      }
    }).generate();
    let { code = '' } = result;
    return code;
  },

  async transformFromAst(ast: t.Node, handle?: Function) {
    let { code = '' } = (await babel.transformFromAstAsync(ast, undefined, {
      ast: false,
      babelrc: false
    }))!;
    code = handle?.(code) as string
    code = await prettifyJs(code);
    return code;
  }
};
